﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml.Serialization;
using System.IO;

namespace ExcelFileQueryTool
{
    public sealed class ToolSettingSectionHandler : IConfigurationSectionHandler
    {
        public object Create(object parent, object configContext, System.Xml.XmlNode section)
        {
            using (TextReader reader = new StringReader("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + section.OuterXml))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(ToolSettings));
                return serializer.Deserialize(reader);
            }
        }
    }


    [XmlRoot("ToolSettings")]
    public sealed class ToolSettings
    {
        [XmlElement(ElementName = "source", Type = typeof(string))]
        public string SourceFolder { get; set; }

        [XmlElement(ElementName = "pattern", Type = typeof(string))]
        public string FilePattern { get; set; }

        [XmlElement(ElementName = "target", Type = typeof(string))]
        public string TargetFolder { get; set; }

        [XmlArray(ElementName = "exclude")]
        [XmlArrayItem(ElementName = "filename", Type = typeof(string))]
        public string[] ExcludeFileNames { get; set; }

        [XmlElement(ElementName = "modifiedTimeAfter", Type = typeof(DateTime))]
        public DateTime? ModifiedTimeAfter { get; set; }

        [XmlElement(ElementName = "clientFileTpl", Type = typeof(string))]
        public String ClientFileTpl { get; set; }


        [XmlElement(ElementName = "dbConnectionString", Type = typeof(string))]
        public string DBConnectionString { get; set; }


        [XmlElement(ElementName = "database", Type = typeof(string))]
        public string Database { get; set; }


        [XmlElement(ElementName = "directPayRecivers", Type = typeof(string))]
        public string DirectPayRecivers { get; set; }

        [XmlArray(ElementName = "nameMappings")]
        [XmlArrayItem(ElementName = "map", Type = typeof(NameMapping))]
        public NameMapping[] NameMappings { get; set; }

        [XmlArray(ElementName = "billNotRequired")]
        [XmlArrayItem(ElementName = "client", Type = typeof(string))]
        public string[] BillNotRequiredClients { get; set; }

        [XmlArray(ElementName = "reportDetailNotRequired")]
        [XmlArrayItem(ElementName = "client", Type = typeof(string))]
        public string[] ReportDetailNotRequiredClients { get; set; }
    }

    public sealed class NameMapping
    {
        [XmlAttribute(AttributeName = "from")]
        public string SourceName { get; set; }

        [XmlAttribute(AttributeName = "to")]
        public string MappedName { get; set; }
    }

    public static class AppConfig
    {
        private static string[] direct_pay_recivers = null;

        private static string _database = null;
        private static string _connStrNoDB = null;
        private static string _dbName = string.Empty;

        public static string[] ClientTypes
        {
            get
            {
                var dirs = Directory.GetDirectories(AppConfig.SourceFolder, "*", SearchOption.TopDirectoryOnly);
                return dirs.Select(x => (new DirectoryInfo(x)).Name).ToArray();
            }
        }

        public static string[] DirectPayRecivers
        {
            get
            {
                if (direct_pay_recivers == null)
                {
                    direct_pay_recivers = Settings.DirectPayRecivers.Split(',');
                }

                return direct_pay_recivers;
            }
        }

        public static string Database
        {
            get
            {
                if (_database == null)
                {
                    const string tag = "Database=";
                    int begin = DBConnectionString.IndexOf(tag, StringComparison.InvariantCultureIgnoreCase) + tag.Length;

                    int end = DBConnectionString.IndexOf(';', begin);
                    if (end < 0)
                        end = DBConnectionString.Length;

                    _database = DBConnectionString.Substring(begin, end - begin);
                }

                return _database;
            }
        }

        public static string DBConnectionStringWithoutDBName
        {
            get
            {
                if (_connStrNoDB == null)
                {
                    int idx = DBConnectionString.IndexOf("Database=", StringComparison.InvariantCultureIgnoreCase);
                    _connStrNoDB = DBConnectionString.Substring(0, idx);
                }

                return _connStrNoDB;
            }
        }

        public static string DBName
        {
            get
            {
                if (_dbName == string.Empty)
                {
                    const string DBNAME_KEY = "Database=";
                    int startIdx = DBConnectionString.IndexOf(DBNAME_KEY, StringComparison.InvariantCultureIgnoreCase) + DBNAME_KEY.Length;
                    int endIdx = DBConnectionString.IndexOf(";", startIdx);
                    if (endIdx < 0)
                        endIdx = DBConnectionString.Length;

                    _dbName = DBConnectionString.Substring(startIdx, endIdx - startIdx);
                }

                return _dbName;
            }
        }

        public static string DBConnectionString { get { return Settings.DBConnectionString; } }

        private static ToolSettings Settings = (ToolSettings)ConfigurationManager.GetSection("ToolSettings");

        public static string SourceFolder { get { return Settings.SourceFolder; } }

        public static string FilePattern { get { return Settings.FilePattern; } }

        public static string[] ExcludeFileNames { get { return Settings.ExcludeFileNames; } }

        public static DateTime ModifiedTimeAfter { get { return Settings.ModifiedTimeAfter.HasValue ? Settings.ModifiedTimeAfter.Value : DateTime.MinValue; } }

        public static string ClientFileTpl { get { return Settings.ClientFileTpl; } }

        public static string[] BillNotRequiredClients { get { return Settings.BillNotRequiredClients; } }

        public static string ClientFileChooseFilter { get { return "Excel 2007 Files(*.xlsx)|*.xlsx"; } }

        public static string WorkLogFileNoteAmountRegexPattern { get { return @"\w+(?<!(?:卸车)|卸|\d)(\d+(?:\.\d+)?)(?:吨|包)"; } }

        /// <summary>
        /// Format:  0-person, 1-phone, 2-address
        /// </summary>
        public static string ClientFileContactInfoFormat { get { return "联系人：{0}   电话：{1}   地址：{2}"; } }

        public static string ClientFileContactInfoRegexPattern { get { return "联系人[:：](.*?)电话[:：](.*?)地址[:：](.*)"; } }

        public static string ClientFileSheetTitleFormat = "&\"-,加粗\"&20";

        public static bool IsClientBillRequireded(string clientName)
        {
            if (string.IsNullOrEmpty(clientName))
                throw new ArgumentNullException("clientName");

            if (BillNotRequiredClients == null || BillNotRequiredClients.Length == 0)
                return true;

            return BillNotRequiredClients.Contains(clientName) == false;
        }

        public static string[] ReportDetailNotRequiredClients { get { return Settings.ReportDetailNotRequiredClients; } }

        public static bool IsClientReportDetailRequireded(string clientName)
        {
            if (string.IsNullOrEmpty(clientName))
                throw new ArgumentNullException("clientName");

            if (ReportDetailNotRequiredClients == null || ReportDetailNotRequiredClients.Length == 0)
                return true;

            return ReportDetailNotRequiredClients.Contains(clientName) == false;
        }

        public static string GetMappedName(string sourceName)
        {
            if (string.IsNullOrEmpty(sourceName))
                return sourceName;

            var mapping = Settings.NameMappings.FirstOrDefault(x => x.SourceName == sourceName);

            if (mapping == null)
                return sourceName;
            else
                return mapping.MappedName;
        }

        public static string GetSourceName(string mappedName)
        {
            if (string.IsNullOrEmpty(mappedName))
                return mappedName;

            var mapping = Settings.NameMappings.FirstOrDefault(x => x.MappedName == mappedName);

            if (mapping == null)
                return mappedName;
            else
                return mapping.SourceName;
        }
    }
}
